package pdfsetter.core.schema.selectors;

import java.util.Iterator;
import java.util.List;

import pdfsetter.core.schema.advanced.FilePageSelection;
import pdfsetter.core.schema.advanced.FilePageSelector;
import pdfsetter.core.util.RandomAccessIterableIterator;

/**
 * CompoundFilePageSelector represents composition of selectors. It works like composition of functions - each selector receive a set of pages and produce new
 * ordered set of pages which is some selection of them (of course we can have repetition of pages). So when we apply selector to some file we can think of the
 * result as an new file and apply another selector and so on.
 * 
 * @author Andrzej Dorobisz
 */
public class CompoundFilePageSelector implements FilePageSelector {
    private final FilePageSelector[] selectors;

    public CompoundFilePageSelector(FilePageSelector... selectors) {
        this.selectors = selectors;
    }

    public CompoundFilePageSelector(List<FilePageSelector> pageSelectors) {
        selectors = new FilePageSelector[pageSelectors.size()];
        int i = 0;
        for (FilePageSelector curSelector : pageSelectors) {
            selectors[i++] = curSelector;
        }
    }

    @Override
    public FilePageSelection selectPages(int fileSize) {
        if (selectors.length > 0 && fileSize > 0)
            return new CompoundFilePageSelection(fileSize);
        else
            return new EmptyFilePageSelection();
    }

    private class CompoundFilePageSelection implements FilePageSelection {
        private final FilePageSelection[] selections;
        private final int size;

        public CompoundFilePageSelection(int fileSize) { // greater than zero, at least one selector
            int curSize = fileSize;
            selections = new FilePageSelection[selectors.length];
            for (int i = 0; i < selectors.length; i++) {
                selections[i] = selectors[i].selectPages(curSize);
                curSize = selections[i].size();
            }
            size = curSize;
        }

        @Override
        public Integer get(int index) {
            if (index >= size || index < 0)
                throw new IndexOutOfBoundsException();
            int curIndex = index;
            for (int i = selections.length - 1; i >= 0; i--) {
                curIndex = selections[i].get(curIndex);
            }
            return curIndex;
        }

        @Override
        public int size() {
            return size;
        }

        @Override
        public Iterator<Integer> iterator() {
            return new RandomAccessIterableIterator<Integer>(this);
        }
    }
}
